// Snagged from postings on Microsoft Silverlight web site
#if NO_SILVERLIGHT
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC.Communication
{
    /// <summary>
    /// Taken from example on internet - find again and give credit where due
    /// </summary>
    public class PolicySocketServer
    {
        TcpListener _Listener = null;
        TcpClient _Client = null;
        public static Lockable _lock = new Lockable();
        //public static ManualResetEvent _TcpClientConnected = new ManualResetEvent(false);
        const string _PolicyRequestString = "<policy-file-request/>";
        int _ReceivedLength = 0;
        byte[] _Policy = null;
        byte[] _ReceiveBuffer = null;
        public bool WantExit;
        private void InitializeData()
        {
            string s = "<access-policy><cross-domain-access><policy><allow-from><domain uri=\"*\" /></allow-from><grant-to><socket-resource port=\"4502\" protocol=\"tcp\" /></grant-to></policy></cross-domain-access></access-policy>";
            _Policy = Encoding.UTF8.GetBytes(s);
            _ReceiveBuffer = new byte[_PolicyRequestString.Length];
        }
        public void StartPolicyListener()
        {
            try
            {
                //Using TcpListener which is a wrapper around a Socket
                //Allowed port is 943 for Silverlight sockets policy data
                _Listener = new TcpListener(IPAddress.Any, 943);
                _Listener.Start();
                // Console.WriteLine("Policy server listening...");
                while (true)
                {
                    //_TcpClientConnected.Reset();
                    _lock.AquireLock();
                    
                    IAsyncResult result = _Listener.BeginAcceptTcpClient(new AsyncCallback(OnBeginAccept), null);

                    while (_lock.Locked)
                        Thread.Sleep(40);
                    // _TcpClientConnected.WaitOne(); //Block until client connects
                
                    if (WantExit)
                        break;

                    Thread.Sleep(30);
                }
            }
            catch (Exception exp)
            {
                LogError(exp);
            }
        }
        public void StartSocketServer()
        {
            InitializeData();
            ThreadStart ts = new ThreadStart(StartPolicyListener);
            Thread t = new Thread(ts);
            t.IsBackground = false;
            t.Start();
        }
        private void OnBeginAccept(IAsyncResult ar)
        {
            _Client = _Listener.EndAcceptTcpClient(ar);

            _Client.Client.BeginReceive(_ReceiveBuffer, 0, _PolicyRequestString.Length, SocketFlags.None,
                new AsyncCallback(OnReceiveComplete), null);
        }

        private void OnReceiveComplete(IAsyncResult ar)
        {
            try
            {
                int bytes = _Client.Client.EndReceive(ar);

                if (bytes >= 0)
                {
                    _ReceivedLength += bytes;
                    //See if there's more data that we need to grab
                    if (_ReceivedLength < _PolicyRequestString.Length)
                    {
                        //Need to grab more data so receive remaining data
                        _Client.Client.BeginReceive(_ReceiveBuffer, _ReceivedLength,
                            _PolicyRequestString.Length - _ReceivedLength,
                            SocketFlags.None, new AsyncCallback(OnReceiveComplete), null);

                        return;
                    }
                    //Check that <policy-file-request/> was sent from client
                    string request = System.Text.Encoding.UTF8.GetString(_ReceiveBuffer, 0, _ReceivedLength);
                    if (StringComparer.InvariantCultureIgnoreCase.Compare(request, _PolicyRequestString) != 0)
                    {
                        //Data received isn't valid so close
                        _Client.Client.Close();
                        return;
                    }
                    //Valid request received....send policy data
                    _Client.Client.BeginSend(_Policy, 0, _Policy.Length, SocketFlags.None,
                        new AsyncCallback(OnSendComplete), null);
                }
            }
            catch (Exception exp)
            {
                _Client.Client.Close();
                LogError(exp);
            }
            _ReceivedLength = 0;

            _lock.ReleaseLock();
            //_TcpClientConnected.Set(); //Allow waiting thread to proceed
        }

        private void OnSendComplete(IAsyncResult ar)
        {
            try
            {
                _Client.Client.EndSendFile(ar);
            }
            catch (Exception exp)
            {
                LogError(exp);
            }
            finally
            {
                //Close client socket
                _Client.Client.Close();
            }
        }
        private void LogError(Exception exp)
        {
            //string appFullPath = Assembly.GetCallingAssembly().Location;
            //string logPath = appFullPath.Substring(0, appFullPath.LastIndexOf("\\")) + ".log";
            //StreamWriter writer = new StreamWriter(logPath, true);
            //try
            //{
            //    writer.WriteLine(logPath,
            //        String.Format("Error in PolicySocketServer: "
            //        + "{0} \r\n StackTrace: {1}", exp.Message, exp.StackTrace));
            //}
            //catch { }
            //finally
            //{
            //    writer.Close();
            //}
        }
    }
}
#endif